/**
 * @file
 * This file contains all excetion id's to ensure they are unique
 */

#ifndef __EXCEPT_H
#define __EXCEPT_H

/** noexception - no exception raised id */
#define noexception 0x0000

/** mem_alloc_failed - exception thrown when malloc fails removing the need to check the return value */
#define mem_alloc_failed (noexception+1)

/** custom_exception - this is the minimum value to start defining user custom exception id's */
#define custom_exception (0xF000)

#define EXCEPT_HANDLING_SETUP \
  struct vector __jump_buf_vct__ = VECTOR_INIT(__jump_buf_vct__)

extern struct vector __jump_buf_vct__;

struct __jump_buf_item__ {
  struct list_head list;
  jmp_buf buf;  
};

#define try                                           \
  do {                                                \
   struct __jump_buf_item__ __item__;                 \
   struct __jump_buf_item__ *__tmp__;                     \
   int __id__ = noexception;                              \
                                                          \
      vect_push_back(&__jump_buf_vct__, &__item__.list);  \
      switch (__id__=setjmp(__item__.buf)) {              \
      case (noexception):

#define catch(id)                               \
          break;                                \
      case (id):

#define endtry                                  \
          break;                                \
      default:                                  \
          throw(__id__);                        \
          break;                                \
      }                                         \
      if (__id__ == noexception) {              \
          vect_pop_back(&__jump_buf_vct__, __tmp__, list); \
      }                                                    \
  } while(0)


#define throw(id)                                               \
  do {                                                          \
   struct __jump_buf_item__ *tmp;                               \
                                                                \
       vect_pop_back(&__jump_buf_vct__, tmp, list);             \
       exassert(tmp != NULL && "Invalid throw statement");      \
       longjmp(tmp->buf, id);                                   \
  } while(0)

#endif /* __EXCEPT_H */
